#ifndef CONSTANTFIELD_HPP
#define CONSTANTFIELD_HPP

#include "meshTypes_fwd.hpp"
#include "solverBaseTypes_fwd.hpp"
#include "fieldBase.hpp"
#include "fieldFunctions.hpp"

namespace hms
{

template<typename _MeshType>
class FieldTraits<ConstantField<NonUniform, _MeshType>> {
public:
	using MeshType = _MeshType;
	using ValueType = const ArrayXXs&;
	using ConstValueType = ValueType;
};

template<typename _MeshType>
class FieldTraits<ConstantField<Uniform, _MeshType>> {
public:
	using MeshType = _MeshType;
	using ValueType = Eigen::Replicate<ArrayXXs, Dynamic, Dynamic>;
	using ConstValueType = ValueType;
};


template<Uniformity _isUniform, typename MeshType>
class ConstantField : public FieldBase<ConstantField<_isUniform, MeshType>> {
public:
	constexpr static Uniformity isUniform {_isUniform};

	using Type = ConstantField<isUniform, MeshType>;
	using ConstValueType = typename FieldTraits<Type>::ConstValueType;

private:
	ArrayXXs m_values;
public:
	ConstantField() = default;
	
	ConstantField( const MeshBase<MeshType>& mesh, ArrayXXs&& values );

	using FieldBase<Type>::values;

	/* provide different accessor than non-const reference to m_values, so that
	 * values can only be set as a whole and not changed accidentally */
	void values( ArrayXXs&& vals ){
		assertFieldValuesSize<isUniform>( vals, this->mesh() );
		m_values = std::move(vals);
		if constexpr (!isUniform)
			setCorners(m_values, this->mesh(), FieldBase<Type>::cornerValue);
	}

	const ArrayXXs& storage() const { return m_values; }

private:
	ConstValueType valuesImp() const {
		if constexpr (isUniform){
			return m_values.replicate(1, nFieldCols( this->mesh() ) );
		} else {
			return m_values;
		}
	}

	decltype(auto) domainValuesImp() const {
		return hms::domainValues(
			this->values(), this->mesh()
		);
	}

	friend FieldBase<Type>;
};

template<Uniformity isUniform, typename MeshType>
ConstantField<isUniform, MeshType>::ConstantField(
	const MeshBase<MeshType>& mesh, ArrayXXs&& vals
) :
	FieldBase<ConstantField<isUniform, MeshType>>(mesh)
{
	values( std::move(vals) );
}

} // end namespace hms

#endif